package com.viknix.threadpool.manager.config.dump;

import com.viknix.threadpool.manager.config.dump.engine.TpmDelayTaskExecuteEngine;
import com.viknix.threadpool.manager.server.dependence.exception.ServerProcessException;
import com.viknix.threadpool.manager.server.dependence.task.AbstractDelayTask;
import lombok.extern.slf4j.Slf4j;

import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

/**
 * @Author: Dongqi
 * @Date: 2021/11/18 19:43
 * @Version 1.0
 * @Description: 任务管理器，旨在处理需要完成的任务。并且该类通过单线程处理任务，以确保任务应该被成功处理。
 */
@Slf4j
public final class TaskManager extends TpmDelayTaskExecuteEngine {

    private String name;

    Condition notEmpty = this.lock.newCondition();

    public TaskManager(String name) {
        super(name, 100L);
        this.name = name;
    }

    /**
     * Close task manager.
     */
    public void close() {
        try {
            super.shutdown();
        } catch (ServerProcessException ignored) {
        }
    }

    /**
     * Await for lock.
     *
     * @throws InterruptedException InterruptedException.
     */
    public void await() throws InterruptedException {
        this.lock.lock();
        try {
            while (!this.isEmpty()) {
                this.notEmpty.await();
            }
        } finally {
            this.lock.unlock();
        }
    }

    /**
     * Await for lock by timeout.
     *
     * @param timeout timeout value.
     * @param unit    time unit.
     * @return success or not.
     * @throws InterruptedException InterruptedException.
     */
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        this.lock.lock();
        boolean isawait = false;
        try {
            while (!this.isEmpty()) {
                isawait = this.notEmpty.await(timeout, unit);
            }
            return isawait;
        } finally {
            this.lock.unlock();
        }
    }

    @Override
    public void addTask(Object key, AbstractDelayTask newTask) {
        super.addTask(key, newTask);
    }

    @Override
    public AbstractDelayTask removeTask(Object key) {
        AbstractDelayTask result = super.removeTask(key);
        return result;
    }

    @Override
    protected void processTasks() {
        super.processTasks();
        if (tasks.isEmpty()) {
            this.lock.lock();
            try {
                this.notEmpty.signalAll();
            } finally {
                this.lock.unlock();
            }
        }
    }

    /**
     * Init and register the mbean object.
     */
    public void init() {
        try {
            ObjectName oName = new ObjectName(this.name + ":type=" + TaskManager.class.getSimpleName());
            ManagementFactory.getPlatformMBeanServer().registerMBean(this, oName);
        } catch (Exception e) {
            log.error("registerMBean_fail", e);
        }
    }
}
